/*
  ECMFS: Edge Core Master Filesystem - A Distributed Encrypted Filesystem
                                       in Userspace based on FUSE.
  Author    : Harsha M.
  Banner Id : A20250275
  Course    : CS549, Fall 2014, Illinois Institute of Technology, Chicago
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include <getopt.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "configfile.h"
#include "server.h"
#include "db.h"
#include "ssl.h"
#include "ecmfs_cmn.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>


#define DEBUG 0

#if DEBUG
#define DEBUG_LOG(fmt , args...) \
    printf("\n[%s][%d] " fmt "\n" , __FUNCTION__, __LINE__ , ##args );
#else
#define DEBUG_LOG(fmt , args... ) 
#endif

ssl_t ecmfs_ssl;
/* local path for .ecmfs directory 
 * individual profile are copied in ~/.ecmfs_path/<login>/profile*/
char *ecmfs_path;
//typedef int my_bool; this is defined in my_global.h
config_file_t *cfile=NULL;
ecmfs_runtime_state_t ecmfs;
int is_ready_to_serve;
int send_notifications(server_state_t state);
int start_server_threads(void);

void usage(char * prog)
{
    fprintf(stderr, "usage:%s <options> \n", prog);
    fprintf(stderr, "options:\n"
            "   --configfile   config file path (mandatory)\n"
            "   --keypassword  password for key handling (mandatory)\n"
            "   --dbpassword   password for db  handling (mandatory)\n"
            "   --genkey       create new keypair and cert\n");
}


int parse_arguments(int argc, char** argv)
{
    int ch, option_index=0;
    const char argstr[]="c:k:d:g:h";
    int config_file_read=0;
    int password_read=0; 
    int dbpassword_read=0;     
    int keys_read=0; 
    int keystore_init=0; 
    
    static struct option long_options[] = {
        {"configfile", required_argument, 0, 'c'},        
        {"keypassword", required_argument, 0, 'k'},
        {"dbpassword", required_argument, 0, 'd'},
        {"genkey", no_argument, 0, 'g'},
        {"help", no_argument, 0, 'h'},
        {0,0,0,0}
    };

    if (argc < 2) {
         usage(argv[0]);
         return -1;
    }

    while ((ch=getopt_long(argc, argv, argstr, 
                    long_options, &option_index)) != -1) {
        switch (ch) {
        case 'c' : {
            if (optarg)
                printf("Config fle=%s\n", optarg); 
            cfile = (config_file_t *) malloc(sizeof(config_file_t));
            config_file_init(cfile,  optarg);
            cfg_ropen(cfile, optarg);
            cfg_read_file(cfile);
            cfg_close(cfile);
            ecmfs_path=cfile->keystore_path;
            config_file_read=1;
            break;
        } 
        case 'k' : {
            if (config_file_read == 0) {
                fprintf(stderr, 
                    "Please provide config file name\n");
                return -1;
            }                
            if (optarg) {
                strncpy(cfile->password, optarg, 32);
            }                
            password_read=1;
            break;
        }
        case 'd' : {
            if (config_file_read == 0) {
                fprintf(stderr, 
                    "Please provide config file name\n");
                return -1;
            } 
            if (password_read == 0) {
                fprintf(stderr, 
                    "Please provide dbpassword\n");
                return -1;
            }             
            if (optarg) {
                strncpy(cfile->db_password, optarg, 32);
            }                
            dbpassword_read=1;
            break;
        }         
        case 'g' : {
            char keyStorePath[256];
            ssl_ret_t ret1, ret2;
            struct stat st = {0};
            int c;
            int rootCreated = 0;
            
            if (config_file_read == 0) {
                fprintf(stderr, 
                    "Please provide config file name\n");
                return -1;
            } 
            if (password_read == 0) {
                fprintf(stderr, 
                    "Please provide keypassword\n");
                return -1;
            }
            if (dbpassword_read == 0) {
                fprintf(stderr, 
                    "Please provide dbpassword\n");
                return -1;
            }            
            init_ssl(); 
            /* certificate and keys for master */
            /* create keystore */
            fprintf(stderr, "Create Keystore..\n");            
            memset(keyStorePath, 0, sizeof(keyStorePath));
            strncpy(keyStorePath, ecmfs_path, 256);
            c = strlen(keyStorePath);
            
            if (stat(keyStorePath, &st) == -1) {
                fprintf(stderr, "%s does not exist:"
                    "creating a dir\n", ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
            strncat(keyStorePath, cfile->my_name, 256);            
            if (stat(keyStorePath, &st) == -1) {
                fprintf(stderr, "%s does not exist in %s;"
                    "creating a dir\n", cfile->my_name,ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
            /* create node encryption and
               sign keys */ 
            set_keyStore_path(&ecmfs_ssl, 
                keyStorePath);
            set_root_ca_cert(&ecmfs_ssl,
                (char *) "ca_cert.pem");
            keystore_init = 1;
            
            fprintf(stderr, "Create Keys..\n");
            fprintf(stderr, "Create Node Encryption Key..\n");
            create_my_encryption_keys(&ecmfs_ssl, 
                (char *)"my_enc_pub.pem",
                (char *)"my_enc_priv.pem", 
                (char *) cfile->password);
            fprintf(stderr, "Create Node Signing Key..\n");
            create_my_signing_keys(&ecmfs_ssl, 
                (char *)"my_sign_pub.pem",
                (char *)"my_sign_priv.pem",
                (char *) cfile->password);
            fprintf(stderr, "Create Node Certificate..\n");
            create_my_cert(&ecmfs_ssl,
                (char *)"my_cert.pem");
            
            fprintf(stderr, "Read back node encryption key..\n");
            ret1 = read_my_encryption_keys(&ecmfs_ssl, 
                (char *)"my_enc_pub.pem",
                (char *)"my_enc_priv.pem", 
                (char *)cfile->password);
            fprintf(stderr, "Read back node signing key..\n");
            ret2 = read_my_signing_keys(&ecmfs_ssl, 
                (char *)"my_sign_pub.pem",
                (char *)"my_sign_priv.pem",
                (char *)cfile->password);
            if ((ret1 == SSL_SUCCESS) && 
                (ret2 == SSL_SUCCESS)){
                keys_read=1;
            }


            /* create  root encryption and sign 
                keys */ 
            memset(keyStorePath, 0, 
                   sizeof(keyStorePath));
            strncpy(keyStorePath, ecmfs_path, 256);
            c = strlen(keyStorePath);
            strncat(keyStorePath, "/root",(256-c)?(256-c):0);
            c = strlen(keyStorePath);
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist:"
                    "creating a dir\n", ecmfs_path);
                mkdir(keyStorePath, 0700);
            }  else {
                printf("%s does exists", ecmfs_path);                
                rootCreated=1;
            }
            strcat(keyStorePath, "/");
            set_keyStore_path(&ecmfs_ssl,
                              keyStorePath);
            
            if ((cfile->my_node_type == CONFIG_MASTER) &&
                (!rootCreated)) {
                fprintf(stderr, "Create Root Encryption Key..\n");
                create_root_encryption_keys(&ecmfs_ssl,
                        (char *)"root_enc_pub.pem",
                        (char *)"root_enc_priv.pem",
                        (char *)cfile->password);
                fprintf(stderr, "Create Root Signing Key..\n");
                create_root_signing_keys(&ecmfs_ssl,
                        (char *)"root_sign_pub.pem",
                        (char *)"root_sign_priv.pem", 
                        (char *)cfile->password);
            }
            fprintf(stderr, "Read back root encryption key..\n");
            ret1 = read_root_encryption_keys(&ecmfs_ssl, 
                (char *)"root_enc_pub.pem",
                (char *)"root_enc_priv.pem", 
                (char *)cfile->password);
            fprintf(stderr, "Read back root signing key..\n");
            ret2 = read_root_signing_keys(&ecmfs_ssl, 
                (char *)"root_sign_pub.pem",
                (char *)"root_sign_priv.pem",
                (char *)cfile->password);
            if (keys_read &&
                (ret1 == SSL_SUCCESS) && 
                (ret2 == SSL_SUCCESS)){
                keys_read=1;
            } else  keys_read=0;               
            
            break;
        }
        break;
        default:
        {
            usage(argv[0]);
            fprintf(stderr, "ignoring option character %c\n", optopt);
            return -1;
        }
    } /* switch */
    } /* while */
    
    if (config_file_read == 0) {
        fprintf(stderr, 
            "Please provide config file name\n");
        return -1;
    } 
    if (password_read == 0) {
        fprintf(stderr, 
            "Please provide keypassword\n");
        return -1;
    }
    if (dbpassword_read == 0) {
        fprintf(stderr, 
            "Please provide dbpassword\n");
        return -1;
    }  
    /* if keys are not read yet, read them now */
    if (!keys_read) {
        char keyStorePath[256];
        ssl_ret_t ret1, ret2, ret3, ret4;
        struct stat st = {0};
        int c;
        
        fprintf(stderr, "Read Keys..\n");
        if (!keystore_init) {
            fprintf(stderr, "Keystore not present, initializing..\n");
            init_ssl(); 
            /* certificate and keys for master */
            /* create keystore */
            memset(keyStorePath, 0, sizeof(keyStorePath));
            strncpy(keyStorePath, ecmfs_path, 256);
            c = strlen(keyStorePath);
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist:"
                    "creating a dir\n", ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
            strncat(keyStorePath, cfile->my_name, 256);   
            if (stat(keyStorePath, &st) == -1) {
                printf("%s does not exist in %s;"
                    "creating a dir\n", cfile->my_name,ecmfs_path);
                mkdir(keyStorePath, 0700);
            } 
            strncat(keyStorePath, "/",(256-c)?(256-c):0);
            
            /* create node encryption and
               sign keys */ 
            set_keyStore_path(&ecmfs_ssl, 
                keyStorePath);
            set_root_ca_cert(&ecmfs_ssl,
                (char *) "ca_cert.pem");
        }
        fprintf(stderr, "Keystore not present, initializing..\n");
        
        fprintf(stderr, "Read node encryption keys..\n");
        ret1 = read_my_encryption_keys(&ecmfs_ssl, 
            (char *)"my_enc_pub.pem",
            (char *)"my_enc_priv.pem", 
            (char *)cfile->password);
        fprintf(stderr, "Read node signing keys..\n");
        ret2 = read_my_signing_keys(&ecmfs_ssl, 
            (char *)"my_sign_pub.pem",
            (char *)"my_sign_priv.pem",
            (char *)cfile->password);
        
        
        memset(keyStorePath, 0, sizeof(keyStorePath));
        strncpy(keyStorePath, ecmfs_path, 256);
        c = strlen(keyStorePath);
        if (stat(keyStorePath, &st) == -1) {
            printf("%s does not exist:"
                "creating a dir\n", ecmfs_path);
            mkdir(keyStorePath, 0700);
        } 
        strncat(keyStorePath, "/",(256-c)?(256-c):0);
        strncat(keyStorePath, "root", 256);   
        if (stat(keyStorePath, &st) == -1) {
            printf("%s does not exist in %s;"
                "creating a dir\n", cfile->my_name,ecmfs_path);
            mkdir(keyStorePath, 0700);
        } 
        strncat(keyStorePath, "/",(256-c)?(256-c):0);        
        set_keyStore_path(&ecmfs_ssl, 
            keyStorePath);
            
        fprintf(stderr, "Read root encryption keys..\n");
        ret3 = read_root_encryption_keys(&ecmfs_ssl, 
            (char *)"root_enc_pub.pem",
            (char *)"root_enc_priv.pem", 
            (char *)cfile->password);
        fprintf(stderr, "Read root signing keys..\n");
        ret4 = read_root_signing_keys(&ecmfs_ssl, 
            (char *)"root_sign_pub.pem",
            (char *)"root_sign_priv.pem",
            (char *)cfile->password);
        if ((ret1 == SSL_SUCCESS) && 
            (ret2 == SSL_SUCCESS) &&
            (ret3 == SSL_SUCCESS) &&
            (ret4 == SSL_SUCCESS)){
            keys_read=1;
        }
    }
    
    if (keys_read == 0) {
       fprintf(stderr, "User keys not available, not able to start\n");
       return -1;        
    } else {
       fprintf(stderr, "User keys read in keystore %s\n", ecmfs_path);
    }
    
    return 1;
}
int say_node_hello();
int node_send_message(char *ip, int port, ecmfs_message_t *msg,
                    bool_ecmfs encrypted);
int copy_from_file(char *buffer, int *buffer_len, char *file_name);
int copy_to_file(char *buffer, int buffer_len, char *file_name);
int handle_initial_response(int sd);
int receive_server_response(int sockfd,unsigned char **buffer,
                            int *buff_len);
/* Following is the initialization code
   If user specifies --genkey on command line
   we will create the keys, if not we assume it is created
   and read it from keystore
 */
int main(int argc, char *argv[])
{
    int ret;
    pthread_t thread_id;
    char keyStorePath[256];
    struct stat st = {0};
    int c;
    
    ret = parse_arguments(argc, argv);
    if (ret != 1)
    {
       fprintf(stderr, "Failure in init config and keystore init\n");
       return -1;         
    }
    
    fprintf(stderr, "Initialise rsa encrypt_decrypt_contexts\n");
    ret = ssl_init_rsa_encrypt_decrypt_contexts(&ecmfs_ssl);
    if (ret != SSL_SUCCESS)
    {
       fprintf(stderr, "Cannot initialise encrypt_decrypt_contexts\n");
       return -1;         
    }   
    fprintf(stderr, "Initialise aes encrypt_decrypt_contexts\n");
    
    ret = ssl_init_aes_encrypt_decrypt_contexts(&ecmfs_ssl);
    if (ret != SSL_SUCCESS)
    {
       fprintf(stderr, "Cannot initialise encrypt_decrypt_contexts\n");
       return -1;         
    } 

    /* Initialise State */
    fprintf(stderr, "Initialise State\n");
    ecmfs.state = SERVER_STATE_INITIALIZING;
    ecmfs.info.node_type = cfile->my_node_type;
    strncpy(ecmfs.info.node_name, cfile->my_name, 32);;
    strncpy(ecmfs.info.node_ip, cfile->my_ip, 32);
    ecmfs.info.node_port = cfile->my_port;
    
    memset(keyStorePath, 0, 
           sizeof(keyStorePath));
    strncpy(keyStorePath, ecmfs_path, 256);
    strcat(keyStorePath, "/");    
    c = strlen(keyStorePath);
    strncat(keyStorePath, cfile->my_name,(256-c)?(256-c):0);
    c = strlen(keyStorePath);
    if (stat(keyStorePath, &st) == -1) {
        printf("%s does not exist:", keyStorePath);
        return -1;
    }  
    strcat(keyStorePath, "/");    
    strcat(keyStorePath, ecmfs_ssl.my_enc_pub_key); 
    ecmfs.info.node_pub_key_len = 2048;
    if (copy_from_file((char *) ecmfs.info.node_pub_key, 
            &ecmfs.info.node_pub_key_len,
              keyStorePath) < 0)
    {
        fprintf(stderr, "Cannot copy publick keys to buffer\n");
        return -1;
    }
    
    /* 1. Create Root Login and Self Node */
    {
        db_ret_t db_ret;
        bool_ecmfs rootAdded = ECMFS_FALSE;
        bool_ecmfs nodeAdded= ECMFS_FALSE; 

        init_params(DB_TYPE_MASTER);
        db_ret = open_db();
        if (db_ret != DB_SUCCESS) {
            fprintf(stderr, 
            "Error in opening db %d", 
            db_ret);
        }
        
        
        db_ret = check_user((char *)"root");
        if (db_ret == DB_SUCCESS) {
            rootAdded = ECMFS_TRUE;
        }


        if (rootAdded == ECMFS_FALSE) {
            DEBUG_LOG("%s", 
            "Add to DB User root, root123\n");
            db_ret = add_user((char *)"root",
                            (char *)"root123");
            if (db_ret != DB_SUCCESS) {
                fprintf(stderr, 
                "Error in adding user %d", 
                db_ret);
            }

        }
        
        db_ret = check_node(ecmfs.info.node_name);
        if (db_ret == DB_SUCCESS) {
            nodeAdded = ECMFS_TRUE;
        }
        
        if (nodeAdded == ECMFS_FALSE) {
            DEBUG_LOG("Add to DB NodeIP(%s) and"
                " Port(%d)\n",
                cfile->my_ip, cfile->my_port);            
            db_ret = add_node(&ecmfs.info);

            if (db_ret != DB_SUCCESS) {
                fprintf(stderr, 
                "Error in adding node info %d",
                 db_ret);
            }
            db_ret = close_db();
        } else {
            DEBUG_LOG("%s", "Node already added in DB\n");        
        }
    }
    set_server_state(SERVER_STATE_INITIALIZING); 

    if (ecmfs.info.node_type == NODE_MASTER) {
        is_ready_to_serve = 1;
    } else {
        say_node_hello();
    }

    if (start_server_threads() >= 0) {
        start_listening(cfile, &thread_id);
        pthread_join(thread_id, NULL);
    } else {
        return -1;
    }
    return ret;
}

/* Server Threads:
   These are pthreads to handle requests.
   Message communincation happens with sys V message queues
*/


int start_server_threads(void)
{
    int ret;
   
       
    if (cfile->my_node_type == CONFIG_MASTER) { 
        /* construct node info */
        ret = create_master_thread();
    } else if (cfile->my_node_type == CONFIG_EDGE){
        /* construct node info */
        ret = create_edge_thread();
    } else if (cfile->my_node_type == CONFIG_CORE){
        ret = create_core_thread();
    }
	return ret;
}


int copy_from_file(char *buffer, int *buffer_len, char *file_name)
{
    FILE *fd;
    int rlen;
    int total_read;
    char *iterBuff;
    char ch;
    fprintf(stderr, "%s: Opening %s\n", __FUNCTION__, file_name);
    fd = fopen(file_name, "r");
    if (!fd) {
        fprintf(stderr, "%s: Cannot open %s\n", __FUNCTION__, file_name);
        return -1;
    }

    rlen = 0;
    total_read = 0;
    iterBuff = buffer;
    do {
        ch = fgetc(fd);
        /*
        fread(buffer+rlen,
                    (*buffer_len - rlen),
                    1,
                    fd);
        */           
        if (ferror(fd)) {
            fprintf(stderr,"%s: error in reading\n", __FUNCTION__);
            break;
        }
        else {

            rlen++;
            
            if (rlen >= *buffer_len) {
                fprintf(stderr,"%s: read %d, buffer capacity %d\n",
                    __FUNCTION__, rlen,  *buffer_len);
                break;
            } else {
                total_read++;
                *iterBuff = ch;
                iterBuff++;
                if (feof(fd)) {
                    fprintf(stderr,"%s: read %d bytes, end of file\n",
                        __FUNCTION__, total_read);
                } else {
                    if (rlen % 128 == 0)
                    fprintf(stderr,
                        "%s: read %d bytes, reading more\n", 
                        __FUNCTION__, total_read);
                }
            }
        }  
    }while (!feof(fd));

    *buffer_len = (total_read - 1);
    
    if (!feof(fd)) {
        fprintf(stderr,"%s: read %d bytes, returning before eof\n", __FUNCTION__, total_read);
        fclose(fd);
        return -1;
    }
    fprintf(stderr,"%s: read %d bytes, returning after eof\n", __FUNCTION__, total_read);
    fclose(fd);    
    return 1;
}


int copy_to_file(char *buffer, int buffer_len, char *file_name)
{
    FILE *fd;
    int wlen;
    int total_written;
    char *iterBuff;
    char ch;
    fprintf(stderr, "%s: Opening %s\n", __FUNCTION__, file_name);
    fd = fopen(file_name, "w");
    if (!fd) {
        fprintf(stderr, "%s: Cannot open %s\n", __FUNCTION__, file_name);
        return -1;
    }

    wlen = 0;
    total_written = 0;
    iterBuff = buffer;
    do {
        if (wlen > buffer_len)
        {
            break;
        }
        ch = *iterBuff; 

       
        fputc(ch, fd);
        wlen++;
        if (ferror(fd)) {
            fprintf(stderr,"%s: error in reading\n", __FUNCTION__);
            break;
        }
        else {
                total_written++;
                iterBuff++;
                if (wlen % 128 == 0)
                    fprintf(stderr,
                        "%s: written %d bytes, writing more\n", 
                        __FUNCTION__, total_written);
        }
    }while (!feof(fd));

    fprintf(stderr,"%s: written %d bytes, returning after eof\n",
                                __FUNCTION__, total_written);
    
    fclose(fd);
    return 1;
}

int say_node_hello()
{
    int msglen;
    ecmfs_message_t *msg;
    int sd;
    
    ecmfs_runtime_state_t *add_runtime_msg;
    
    /* Say Hello to Master,Once Master acknowledges without
       additional requests,we are good to go.
    */

    add_runtime_msg = (ecmfs_runtime_state_t *) 
            malloc(sizeof(ecmfs_runtime_state_t));
    if (!add_runtime_msg) {
       fprintf(stderr, "no memory for add_runtime_msg\n");
        return -1;
    }
    
    memset(add_runtime_msg, 0, sizeof(ecmfs_runtime_state_t));
    memcpy(add_runtime_msg, &ecmfs, sizeof(ecmfs_runtime_state_t));
    msglen = sizeof(ecmfs_message_t)+
            sizeof(ecmfs_runtime_state_t);
    fprintf(stderr, "Allocating %d bytes for ecmfs_message_t\n",msglen);                
    msg = (ecmfs_message_t *) malloc(msglen);
    if (!msg) {
       fprintf(stderr, "no memory for ecmfs_message_t\n");
       free(add_runtime_msg);
       return -1;
    }    
    
    memset(msg,0, msglen);
    msg->magic_num = MAGIC_NUM;
    msg->from = add_runtime_msg->info.node_type;
    msg->to = NODE_MASTER;
    msg->type = SERVER_OP_HELLO;
    msg->message_len = sizeof(ecmfs_runtime_state_t);
    msglen = msg->message_len;
    printf("Sending %d bytes of message to master\n", msglen); 
    memcpy(msg->message, add_runtime_msg, msglen);
    sd = node_send_message(cfile->master_ip, cfile->master_port,
                                    msg, ECMFS_FALSE); 
    if (sd > 0) {
        /*msg was sent.... listen to master's response */
        handle_initial_response(sd);
    }
    free(add_runtime_msg);
    free(msg);
    add_runtime_msg = NULL;
    msg = NULL;
    
    return 1;
}

int handle_initial_response(int sd)
{
    unsigned char *response_buffer;
    int response_length;
    int more;
    
    more = 0;
    do {
        receive_server_response(sd, &response_buffer,
                            &response_length);
 
        edge_handle_message(response_buffer, 
                            response_length, &more);
        free(response_buffer);
        response_buffer=NULL;
        response_length=0;
    }
    while(more);
    
    return 1;
}

int receive_server_response(int sockfd,unsigned char **buffer,
                            int *buff_len)
{
    int read_len, avail_len, max_len, min_len, step_len;
    int n;
    unsigned char *buff_start;
    unsigned char *buff;
    
    /* Now read server response */
    max_len = 4096;
    step_len = 1024;
    min_len = 256;
    buff_start = (unsigned char *) malloc(max_len);
    buff = buff_start;
    read_len = 0;
    avail_len = max_len;
    bzero(buff_start,max_len);

    //do {
        DEBUG_LOG("Waiting to read from server:\n");
        n = read(sockfd,buff,avail_len);
        if (n < 0) 
        {
             fprintf(stderr, "ERROR reading from socket %d(%s)", 
                 errno, strerror(errno));
            *buffer = buff_start;
            *buff_len = read_len;
            return 1;
        }

        read_len += n;
        avail_len -=n;
        DEBUG_LOG("read %d characters %d available to read\n",
            read_len,avail_len); 
        
        if (avail_len > min_len) {
            buff += n;
        } else {
            max_len+=step_len;
            avail_len+=step_len;
            buff_start = (unsigned char *)realloc(buff_start, max_len);
            buff = buff_start + read_len;
        }
        
    //} while(n > 0);
    *buffer = buff_start;
    *buff_len = read_len;
    DEBUG_LOG("read %d characters returning\n",read_len);
    return 1;
}

int node_send_message(char *ip, int port, 
                ecmfs_message_t *msg, bool_ecmfs encrypted)
{
    int sockfd, portno, n, writelen;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    int header_len, total_len;
    struct in_addr ipv4addr;    



    dump_ecmfs_message(msg);
    
    
    inet_aton(ip, &ipv4addr);
    //DEBUG_LOG("Server: %s:%x\n", ip, ipv4addr.s_addr);
    

    
    server = gethostbyaddr(&ipv4addr, sizeof(ipv4addr), AF_INET);    
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        return -1;
    }
    portno = port;
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
           (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);
    serv_addr.sin_port = htons(portno);
    //DEBUG_LOG("server->h_addr = %p; serv_addr.sin_port=%d\n",
     //   server->h_addr,serv_addr.sin_port );

    /* Create a socket point */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
    {
        fprintf(stderr, "ERROR opening socket %d(%s)",
                    errno, strerror(errno));
        return -1;
    }
    /* connect to the server */
    //DEBUG_LOG("Connect to Server: sockfd = %d\n", sockfd);
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) 
    {
        fprintf(stderr, "ERROR connecting %d(%s)",
                    errno, strerror(errno));
        return -1;
    }	
    header_len = 
    sizeof(msg->magic_num) + 
    sizeof(msg->from) +
    sizeof(msg->to) +
    sizeof(msg->type) + 
    sizeof(msg->extra) +     
    sizeof(msg->message_len);
    total_len = header_len + msg->message_len;
    
    /* Send message to the server */
    
    writelen = 0;
    do {
        //DEBUG_LOG("Server: %s; total_len=%d, write_len=%d\n",
        //    cfile->master_ip,total_len,writelen);
        n = write(sockfd,((char *)msg )+ writelen,total_len-writelen);
        if (n < 0) 
        {
            fprintf(stderr, "ERROR writing to socket %d(%s)",
                        errno, strerror(errno));
            return -1;
        }
        writelen += n;
    } while(writelen < total_len);
    //DEBUG_LOG("%s", "Writing to server done\n");    
    return sockfd;
}

server_state_t get_server_state(void)
{
    return ecmfs.state;
}
void set_server_state(server_state_t newstate)
{
    if (ecmfs.state == newstate) {
        return;
    }
    switch(ecmfs.state) {
    case SERVER_STATE_INITIALIZING:
        if (newstate == SERVER_STATE_EDGE_READY)
        {
            //DEBUG_LOG("%s: State Change From %d to %d\n",
            //  __FUNCTION__,  ecmfs.state, SERVER_STATE_EDGE_READY);
            
            ecmfs.state = SERVER_STATE_EDGE_READY;

        } else if (newstate == SERVER_STATE_CORE_READY) 
        {
            //DEBUG_LOG("%s: State Change From %d to %d\n",
            // __FUNCTION__,   ecmfs.state, SERVER_STATE_CORE_READY);
            
            ecmfs.state = SERVER_STATE_CORE_READY;
        } else 
        {
            fprintf(stderr, "Unknown state transition old %d new %d",
                ecmfs.state, newstate);            
        }
        break;
    case SERVER_STATE_READY:
        if (newstate == SERVER_STATE_EDGE_READY)
        {
            
            //DEBUG_LOG("%s: State Change From %d to %d\n",
            //  __FUNCTION__,  ecmfs.state, SERVER_STATE_READY);            
            ecmfs.state = SERVER_STATE_READY;
        } else if (newstate == SERVER_STATE_CORE_READY) 
        {
            //DEBUG_LOG("%s: State Change From %d to %d\n",
            //  __FUNCTION__,  ecmfs.state, SERVER_STATE_READY);             
            ecmfs.state = SERVER_STATE_READY;
        } else 
        {
            fprintf(stderr, "Unknown state transition old %d new %d",
                ecmfs.state, newstate);            
        }
        break;
    case SERVER_STATE_EDGE_READY:
        if (newstate == SERVER_STATE_EDGE_READY)
        {
            DEBUG_LOG("%s: State Change From %d to %d\n",
              __FUNCTION__,  ecmfs.state, SERVER_STATE_EDGE_READY);             
            ecmfs.state = SERVER_STATE_EDGE_READY;
        } else if (newstate == SERVER_STATE_CORE_READY) 
        {
            
            DEBUG_LOG("%s: State Change From %d to %d\n",
               __FUNCTION__, ecmfs.state, SERVER_STATE_READY);            
            ecmfs.state = SERVER_STATE_READY;
            send_status_notifications();            
        } else 
        {
            fprintf(stderr, "Unknown state transition old %d new %d",
                ecmfs.state, newstate);             
        }
        break;
    case SERVER_STATE_CORE_READY:
        if (newstate == SERVER_STATE_EDGE_READY)
        {
            DEBUG_LOG("%s: State Change From %d to %d\n",
               __FUNCTION__, ecmfs.state, SERVER_STATE_READY);              
            ecmfs.state = SERVER_STATE_READY;
            send_status_notifications();
        } else if (newstate == SERVER_STATE_CORE_READY) 
        {
            DEBUG_LOG("%s: State Change From %d to %d\n",
               __FUNCTION__, ecmfs.state, SERVER_STATE_CORE_READY);            
            ecmfs.state = SERVER_STATE_CORE_READY;
        } else 
        {
            fprintf(stderr, "Unknown state transition old %d new %d",
                ecmfs.state, newstate);            
        }
        break;
    default:
            fprintf(stderr, "Unknown state transition old %d new %d",
                ecmfs.state, newstate); 
    }
    return;
}

void send_response(int sd, void *arg,
            server_resp_t respType, bool_ecmfs  encrypted,
            node_type_t node_type)
{
    int totalLen=0;
    int n, writelen;
    ecmfs_message_t *msg=NULL;
    ecmfs_server_response_t *response=NULL;
    char *user_id = (char *) arg;
    
    switch(respType) 
    {
        case SERVER_RESP_UNKNOWN:
            DEBUG_LOG("%s sending SERVER_RESP_UNKNOWN len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));
            
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t);
            
            response = (ecmfs_server_response_t *) &msg->message[0];
            response->msg_len = 0;  
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;
            break;
        case SERVER_RESP_HELLO:
            DEBUG_LOG("%s sending SERVER_RESP_HELLO len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));            
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }
            memset(msg, 0, sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            msg->message_len = sizeof(ecmfs_server_response_t);
          
            response = (ecmfs_server_response_t *) &msg->message[0];            
            response->msg_len = 0;  
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;
            break;
        case SERVER_RESP_WHOAREYOU:
            DEBUG_LOG("%s sending SERVER_RESP_WHOAREYOU len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));             
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t);
            
            response = (ecmfs_server_response_t *) &msg->message[0];            
            response->msg_len = 0;  
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;
            break;
        case SERVER_RESP_SENDING_PUBKEY:
            /* send all master and 
               edge public keys
             */
            DEBUG_LOG("%s sending SERVER_RESP_SENDING_PUBKEY len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t) +
                        sizeof(ecmfs_runtime_state_t));              

            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t) +
                        sizeof(ecmfs_runtime_state_t)+3);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t)
                                + sizeof(ecmfs_runtime_state_t);
            print_runtime_state(&ecmfs);
            response = (ecmfs_server_response_t *) &msg->message[0];
            memcpy(&response->msg[0],&ecmfs,
                        sizeof(ecmfs_runtime_state_t));
            response->msg_len = sizeof(ecmfs_runtime_state_t);            
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;
            break;
        case SERVER_RESP_DONE:
            DEBUG_LOG("%s sending SERVER_RESP_DONE len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));             
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t);
            
            response = (ecmfs_server_response_t *) &msg->message[0];
            response->msg_len = 0;            
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;            
            break;
        case SERVER_RESP_ERROR:    
            DEBUG_LOG("%s sending SERVER_RESP_ERROR len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));             
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t);
            memcpy(&response->msg[0],&ecmfs,
                        sizeof(ecmfs_runtime_state_t));            
            response = (ecmfs_server_response_t *) &msg->message[0];
            response->msg_len = 0;            
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;            
            break;
        case SERVER_RESP_INTERNAL_ERROR:
            DEBUG_LOG("%s sending SERVER_RESP_INTERNAL_ERROR len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t));               
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t)+2);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t);
            
            response = (ecmfs_server_response_t *) &msg->message[0];
            response->msg_len = 0;
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;            
            break; 
        case SERVER_RESP_MOUNT_OK:
            {
                session_aes_key_t *sess = (session_aes_key_t *) arg;
            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                +  sizeof(ecmfs_server_response_t) +
                sizeof(session_aes_key_t)+3);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t) +
                sizeof(session_aes_key_t);
            
            response = (ecmfs_server_response_t *) &msg->message[0];
            response->msg_len = sizeof(session_aes_key_t);
            response->state = get_server_state();
            response->more = 0;
            response->resp = respType;  
            memcpy(response->msg,sess,sizeof(session_aes_key_t));
            }
            break;            
       default:
           break;
    }

    msg->magic_num = MAGIC_NUM;
    msg->to = node_type;
    msg->from = NODE_MASTER;
    msg->type = MASTER_OP_RESPONSE;
    totalLen = (sizeof(ecmfs_message_t) +
        + sizeof(ecmfs_server_response_t));
    if (response) totalLen += response->msg_len;
    
    if (encrypted) {
        /* encrypt on user_id key before sending */
        if (node_type == NODE_CLIENT) {
            
             ssl_ret_t ret;
             char pub_key_file_name[100];
             EVP_PKEY *pPubKey;
             unsigned char* encode_buffer;
             int encode_bufsize;
             
             strcpy(pub_key_file_name,user_id);
             strcat(pub_key_file_name,"_pub.key");


       
             ret = read_rsa_pub_key(&ecmfs_ssl, pub_key_file_name,&pPubKey);
             if (SSL_SUCCESS !=  ret) {
                 fprintf(stderr, 
                     "Error in converting Pub key file to EVP_KEY\n");
                 fprintf(stderr, "Freeing up %p\n",msg);        
                 free(msg);                 
                 return;
             }
             ret = encode_rsa_message(&ecmfs_ssl,pPubKey,
                        (unsigned char *)msg, totalLen, 
                        &encode_buffer, &encode_bufsize);
             if (SSL_SUCCESS !=  ret) {
                 fprintf(stderr, 
                     "Error in encoding\n");
                 fprintf(stderr, "Freeing up %p\n",msg);
                 /* also free up EVP Key */
                     EVP_PKEY_free(pPubKey);
                 free(msg);                 
                 return;
             }             
             
             if (msg) {
                   fprintf(stderr, "Freeing up %p\n",msg);        
                   free(msg);
             } 
             EVP_PKEY_free(pPubKey);
             msg = (ecmfs_message_t *) encode_buffer;
             totalLen = encode_bufsize;
        }
    } else {
        /* send sraight away in plain */
    }
    
    
    DEBUG_LOG("Sending out message through sd=%d\n",sd);
    dump_ecmfs_message(msg);
    writelen = 0;
    do {
        n = write(sd,msg+writelen,totalLen-writelen);
        
        if (n < 0) 
        {
            fprintf(stderr, "ERROR writing to socket %d(%s)",
                        errno, strerror(errno));
            close(sd);
            free(msg);
            return;
        }
        writelen += n;
    } while(writelen < totalLen);
    
    //close(sd);
    if (msg) {
       fprintf(stderr, "Freeing up %p\n",msg);        
       free(msg);
    }
    return;    
}

void send_notify(char *ip, int port,void *arg,
            server_resp_t respType, 
            bool_ecmfs  encrypted,
            node_type_t node_type)
{
    int totalLen=0;
    ecmfs_message_t *msg=NULL;
    ecmfs_server_response_t *response=NULL;
    int sd;
    char *user_id = (char *) arg;
    
    switch(respType) 
    {
        case SERVER_NOTIFY_STATUS_UPDATE:
            /* send all master and 
               edge public keys
             */
            DEBUG_LOG("%s sending SERVER_NOTIFY_STATUS_UPDATE len=%d", __FUNCTION__,
                sizeof(ecmfs_server_response_t) +
                        sizeof(ecmfs_runtime_state_t));              

            msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                + sizeof(ecmfs_server_response_t) +
                        sizeof(ecmfs_runtime_state_t)+3);
            
            if (msg == NULL) {
               fprintf(stderr, "Memory allocation failure"); 
               return;
            }              
            msg->message_len = sizeof(ecmfs_server_response_t)
                                + sizeof(ecmfs_runtime_state_t);
            print_runtime_state(&ecmfs);
            response = (ecmfs_server_response_t *) &msg->message[0];
            memcpy(&response->msg[0],&ecmfs,
                        sizeof(ecmfs_runtime_state_t));
            response->msg_len = sizeof(ecmfs_runtime_state_t);            
            response->state = get_server_state();
            response->resp = respType;
            break;
        case SERVER_NOTIFY_SESSION_UPDATE:
            {
                session_aes_key_t *sess = (session_aes_key_t *) arg;
                msg = (ecmfs_message_t *) malloc(sizeof(ecmfs_message_t) +
                +  sizeof(ecmfs_server_response_t) +
                sizeof(session_aes_key_t)+3);
            
                if (msg == NULL) {
                    fprintf(stderr, "Memory allocation failure"); 
                    return;
                }              
                msg->message_len = sizeof(ecmfs_server_response_t) +
                    sizeof(session_aes_key_t);
                
                response = (ecmfs_server_response_t *) &msg->message[0];
                response->msg_len = sizeof(session_aes_key_t);
                response->state = get_server_state();
                response->resp = respType;  
                memcpy(response->msg,sess,sizeof(session_aes_key_t));           
                break;
            }
        default:
            break;
    }

    msg->magic_num = MAGIC_NUM;
    msg->to = node_type;
    msg->from = NODE_MASTER;
    msg->type = MASTER_OP_NOTIFICATION;
    totalLen = (sizeof(ecmfs_message_t) +
        + sizeof(ecmfs_server_response_t));
    if (response) totalLen += response->msg_len;
    
    if (encrypted) {
        /* encrypt on user_id key before sending */
    } else {
        /* send sraight away in plain */
    }
    
    
    DEBUG_LOG("Sending out message through ip=%s port=%d\n",
        ip, port);
    dump_ecmfs_message(msg);
    sd = node_send_message(ip, port, msg, ECMFS_FALSE); 
    if (sd > 0) {
        /*Blind messages for notify....need not wait for response*/
        //handle_initial_response(sd);
    }
    return;    
}

void send_status_notifications(void)
{
    db_ret_t db_ret;
    int i;
    node_details_t *n;
    int count;
    
    db_ret = open_db();
    if (db_ret != DB_SUCCESS) {
        fprintf(stderr, 
        "Error in opening db %d", 
        db_ret);
    }

    db_ret = get_nodes(&n,&count);
    db_ret = close_db();
    
    for (i = 0; i < count; i++)
    {
        node_type_t nt;
        /* this is temporary. We shoud retrieve
           the types also from database only
         */
        if (strcmp(n[i].node_name, "edge1") == 0)
            nt = NODE_EDGE;
        else if (strcmp(n[i].node_name, "core1") == 0)
            nt = NODE_CORE;
        else if (strcmp(n[i].node_name, "master1") == 0)
            nt = NODE_MASTER;
        
        if (strcmp(n[i].node_name, ecmfs.info.node_name) != 0)
        {
            /* send notifications except myself */
            send_notify(n[i].node_ip, n[i].port, NULL,
                SERVER_NOTIFY_STATUS_UPDATE,
                ECMFS_FALSE, nt);
        }
    }
}

void dump_ecmfs_message(ecmfs_message_t *msg)
{
   printf("magic_num=%d\n", msg->magic_num);
   printf("to=%d\n", msg->to);
   printf("from=%d\n", msg->from); 
   printf("type=%d\n",msg->type);
   printf("message_len=%d\n",msg->message_len);
}



ecmfs_msg_queue_t *ecmfs_message_queue_init(void)
{
    ecmfs_msg_queue_t *ecmfs_mq = NULL;
    

    ecmfs_mq = (ecmfs_msg_queue_t *) 
    malloc (sizeof(ecmfs_msg_queue_t));
    if (NULL == ecmfs_mq) {
        fprintf (stderr, "Server:%s alloc failure for queue\n", 
                    __FUNCTION__);
            
        return NULL;            
    }
    memset(ecmfs_mq, 0, sizeof(ecmfs_msg_queue_t));
    
    /* Master */
    pthread_mutex_init (&ecmfs_mq->mq_mutex, NULL);
        
    return ecmfs_mq;
}

void ecmfs_message_queue_deinit(ecmfs_msg_queue_t *ecmfs_mq)
{
    char *msg;
    int msgLen;
    int extra;
    
    while(ecmfs_message_queue_count(ecmfs_mq) > 0) {
        ecmfs_message_queue_del(ecmfs_mq,&msg,&msgLen, &extra);
        free(msg);
    }
    free(ecmfs_mq);
}

int ecmfs_message_queue_add(ecmfs_msg_queue_t *ecmfs_mq,
                            void *msg, int msgLen, int extra)
{
    ecmfs_msg_queue_node_t *node;
    ecmfs_msg_queue_node_t *tmp;
    if (ecmfs_mq != NULL) {
        node = (ecmfs_msg_queue_node_t *) 
        malloc (sizeof(ecmfs_msg_queue_node_t));
        if (NULL == node) {
        fprintf (stderr, "Server:%s node alloc failure\n", 
                    __FUNCTION__);
            
            return -1;
        }
        memset(node, 0, sizeof(ecmfs_msg_queue_node_t));
        node->message_len = msgLen;
        node->extra = extra;
        node->msg = malloc(msgLen);
        
        fprintf (stderr, "Server:%s allocated %d to %p\n", 
                    __FUNCTION__, msgLen, node->msg);
        
        if (NULL == node->msg) {
            fprintf (stderr, "Server:%s buffer alloc failure\n", 
                    __FUNCTION__);
            return -1;
        }
        memcpy(node->msg, msg, msgLen);
        fprintf (stderr, "Server:%s copied %d to %p from %p\n", 
                    __FUNCTION__, msgLen, node->msg, msg);        
        if (ecmfs_mq->head == NULL) {
            /* first node,head and tail are same */
            ecmfs_mq->head = ecmfs_mq->tail = node;
        } else {
            /* add to tail */
            tmp = ecmfs_mq->tail;
            tmp->next = node;
            node->previous = tmp;
            /* update tail */
            ecmfs_mq->tail = node;
        }
        
        ecmfs_mq->num_of_messages++;
    } else {
        fprintf (stderr, "Server:%s queue already inited\n", 
                    __FUNCTION__);
    }
    return 0;
}

int ecmfs_message_queue_del(ecmfs_msg_queue_t *ecmfs_mq,
                            char **msg, int *msgLen, int *extra)
{
    ecmfs_msg_queue_node_t *node;

    if (ecmfs_mq != NULL) {
        if (!ecmfs_mq->num_of_messages) {
            //fprintf (stderr, "Server:%s no message in queue\n", 
            //        __FUNCTION__);
            *msg =  NULL;
            *msgLen = 0;
            return -1;
        }
        /* remove from head */
        node = ecmfs_mq->head;
        ecmfs_mq->head = ecmfs_mq->head->next;
        
        /* copy the message */
        *msg = (char *)  node->msg;
        *msgLen =  node->message_len;
        *extra = node->extra;
        free(node);
        
        ecmfs_mq->num_of_messages--;
    } else {
        fprintf (stderr, "Server:%s queue not initialised\n", 
                __FUNCTION__);
        *msg =  NULL;
        *msgLen = 0;
        return -1;
    }
    return 0;
}

int ecmfs_message_queue_count(ecmfs_msg_queue_t *ecmfs_mq) 
{
    if (ecmfs_mq)
    return ecmfs_mq->num_of_messages;
    else
    return  -1;    
}


void print_runtime_state(ecmfs_runtime_state_t *ecmfs)
{
    int i=0;
    printf("node state = %d\n", ecmfs->state);

    printf("node_name = %s\n", ecmfs->info.node_name);
    printf("node_type = %d\n", ecmfs->info.node_type);
    printf("node_ip = %s\n", ecmfs->info.node_ip);    
    printf("node_port = %d\n", ecmfs->info.node_port);
    printf("node_pub_key_len = %d\n", ecmfs->info.node_pub_key_len);
    
    
    printf("node_pub_key = \n");

    while (i <  ecmfs->info.node_pub_key_len) 
    {
        printf("%c", ecmfs->info.node_pub_key[i]);
        i++;
    }
}
  

void print_user_info(ecmfs_add_user_t *addMsg)
{
    int i=0;
    printf("request to check user %s", addMsg->user_id);
    printf("public key len %d", addMsg->user_pub_key_len);
    
    printf("user_pub_key = \n");

    while (i <  addMsg->user_pub_key_len) 
    {
        printf("%c", addMsg->user_pub_key[i]);
        i++;
    }
}
  
int store_node_public_key(ecmfs_runtime_state_t *nodeState)
{
    char keyStorePath[256];
    int c;

    
    fprintf (stderr, "Node %s sending its public key\n",
        nodeState->info.node_name);
    
    memset(keyStorePath, 0, 
           sizeof(keyStorePath));
    strncpy(keyStorePath, ecmfs_path, 256);
    strcat(keyStorePath, "/");    
    c = strlen(keyStorePath);
    strncat(keyStorePath, cfile->my_name,(256-c)?(256-c):0);
    c = strlen(keyStorePath);
    strcat(keyStorePath, "/");    
    strncat(keyStorePath, nodeState->info.node_name,
                        (256-c)?(256-c):0); 
    strncat(keyStorePath, "_pub.key",
                    (256-c)?(256-c):0); 
    print_runtime_state(nodeState);
    copy_to_file((char *)nodeState->info.node_pub_key, 
                nodeState->info.node_pub_key_len,
                keyStorePath);
    return 0;
}

int store_user_public_key(ecmfs_add_user_t *addMsg)
{
    char keyStorePath[256];
    int c;

    
    fprintf (stderr, "User %s sending public key\n",
        addMsg->user_id);
    
    memset(keyStorePath, 0, 
           sizeof(keyStorePath));
    strncpy(keyStorePath, ecmfs_path, 256);
    strcat(keyStorePath, "/");    
    c = strlen(keyStorePath);
    strncat(keyStorePath, cfile->my_name,(256-c)?(256-c):0);
    c = strlen(keyStorePath);
    strcat(keyStorePath, "/");    
    strncat(keyStorePath, addMsg->user_id,
                        (256-c)?(256-c):0); 
    strncat(keyStorePath, "_pub.key",
                    (256-c)?(256-c):0); 
    print_user_info(addMsg);
    copy_to_file((char *)addMsg->user_pub_key, 
                addMsg->user_pub_key_len,
                keyStorePath);
    return 0;
}
